﻿using IOP.Net;
using IOP.Pulsar.Abstractions;
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IOP.Pulsar.Default
{
    /// <summary>
    /// 默认原始嵌套字生产线入口
    /// </summary>
    public class DefaultRawSocketProductLineEntry : IProductLineEntry<RawSocketContext>
    {
        /// <summary>
        /// 包缓存
        /// </summary>
        public readonly ConcurrentQueue<RawSocketContext> Packages = new ConcurrentQueue<RawSocketContext>();
        /// <summary>
        /// 生产线
        /// </summary>
        public ProductLineDelegate<RawSocketContext> ProductLine { get; set; }
        /// <summary>
        /// 连接
        /// </summary>
        public SocketMonitor ConnectedSocket { get; set; }

        /// <summary>
        /// 队列信号控制器
        /// </summary>
        private readonly AutoResetEvent _QueueResetEvent = new AutoResetEvent(false);

        /// <summary>
        /// 是否被回收
        /// </summary>
        private bool _IsDispose = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="productLine"></param>
        public DefaultRawSocketProductLineEntry(IProductLine<RawSocketContext> productLine)
        {
            if (productLine == null) throw new ArgumentNullException(nameof(productLine));
            ProductLine = productLine.ProductLine;
        }

        /// <summary>
        /// 入口处理函数
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="socket"></param>
        public void EntryHandle(ref ReadOnlySequence<byte> queue, SocketMonitor socket)
        {
            if (ConnectedSocket == null) ConnectedSocket = socket;
            do
            {
                queue = queue.Slice(queue.Length, 0);
            }
            while (!queue.IsEmpty);
        }

        /// <summary>
        /// 回收
        /// </summary>
        public void Dispose()
        {
            ConnectedSocket.ConnectedSocket.Shutdown(SocketShutdown.Both);
            ConnectedSocket.ConnectedSocket.Close();
            ConnectedSocket.ConnectedSocket.Dispose();
        }

        /// <summary>
        /// 队列任务
        /// </summary>
        private void QueueTask()
        {
            Task.Factory.StartNew(() =>
            {
                while (!_IsDispose)
                {
                    while (!Packages.IsEmpty)
                    {
                        Packages.TryDequeue(out RawSocketContext context);
                        ProductLine?.Invoke(context);
                    }
                    _QueueResetEvent.WaitOne();
                }
            });
        }
    }
}
